<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="dmUOD" id="dmUOD"><span data-lake-id="ubdab3c52" id="ubdab3c52">典型回答</span></h1>
  <p data-lake-id="u186f474d" id="u186f474d"><br></p>
  <p data-lake-id="ue27ad6e3" id="ue27ad6e3"><span data-lake-id="u9e53b64e" id="u9e53b64e">Unsafe是CAS的核心类。</span><strong><span data-lake-id="u3de57250" id="u3de57250">因为Java无法直接访问底层操作系统，而是通过本地（native）方法来访问。不过尽管如此，JVM还是开了一个后门，JDK中有一个类Unsafe，它提供了硬件级别的原子操作。</span></strong></p>
  <p data-lake-id="u7745ca7a" id="u7745ca7a"><span data-lake-id="ufb5c0b2c" id="ufb5c0b2c">​</span><br></p>
  <p data-lake-id="ufb758a70" id="ufb758a70"><span data-lake-id="u71d32bdf" id="u71d32bdf">Unsafe是Java中一个底层类，包含了很多基础的操作，比如数组操作、对象操作、内存操作、CAS操作、线程(park)操作、栅栏（Fence）操作，JUC包、一些三方框架都使用Unsafe类来保证并发安全。</span></p>
  <p data-lake-id="uee034e16" id="uee034e16"><span data-lake-id="u48559343" id="u48559343">​</span><br></p>
  <p data-lake-id="ub6f8567e" id="ub6f8567e"><span data-lake-id="u0567ba0d" id="u0567ba0d">Unsafe类在jdk 源码的多个类中用到，这个类的提供了一些绕开JVM的更底层功能，基于它的实现可以提高效率。但是，它是一把双刃剑：正如它的名字所预示的那样，它是Unsafe的，它所分配的内存需要手动free（不被GC回收）。Unsafe类，提供了JNI某些功能的简单替代：确保高效性的同时，使事情变得更简单。</span></p>
  <p data-lake-id="u885c4874" id="u885c4874"><span data-lake-id="u0b83af7f" id="u0b83af7f">​</span><br></p>
  <p data-lake-id="ue17a187c" id="ue17a187c"><span data-lake-id="uc64b9fbe" id="uc64b9fbe">Unsafe类提供了硬件级别的原子操作，主要提供了以下功能：</span></p>
  <p data-lake-id="ub51e6e36" id="ub51e6e36"><span data-lake-id="u9547ec77" id="u9547ec77">1、通过Unsafe类可以分配内存，可以释放内存；</span></p>
  <p data-lake-id="ua1080857" id="ua1080857"><span data-lake-id="u0030eaec" id="u0030eaec">2、可以定位对象某字段的内存位置，也可以修改对象的字段值，即使它是私有的；</span></p>
  <p data-lake-id="ue726dc33" id="ue726dc33"><span data-lake-id="u5b2a18b8" id="u5b2a18b8">3、将线程进行挂起与恢复</span></p>
  <p data-lake-id="u86a7ef45" id="u86a7ef45"><span data-lake-id="uc385ac67" id="uc385ac67">4、CAS操作</span></p>
  <p data-lake-id="uec444c45" id="uec444c45"><span data-lake-id="u5cbe6d02" id="u5cbe6d02">​</span><br></p>
  <p data-lake-id="u748c379e" id="u748c379e"><span data-lake-id="u7d70f0fe" id="u7d70f0fe">​</span><br></p>
  <h1 data-lake-id="Tpe7H" id="Tpe7H"><span data-lake-id="ua5bb9631" id="ua5bb9631">举例</span></h1>
  <p data-lake-id="ue844ffda" id="ue844ffda"><br></p>
  <p data-lake-id="u0106291c" id="u0106291c"><span data-lake-id="ue7b9e5fe" id="ue7b9e5fe" style="color: rgb(74, 74, 74)">Unsafe 被设计的初衷，并不是希望被一般开发者调用，它的构造方法是私有的，所以我们不能通过 new 或者工厂方法去实例化 Unsafe 对象，通常可以采用反射的方法获取到 Unsafe 实例：</span></p>
  <p data-lake-id="uf0943f31" id="uf0943f31"><span data-lake-id="u3449650a" id="u3449650a" style="color: rgb(74, 74, 74)">​</span><br></p>
  <pre lang="java"><code>
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
</code></pre>
  <p data-lake-id="u9b78a085" id="u9b78a085"><br></p>
  <blockquote data-lake-id="u324ccdac" id="u324ccdac">
   <p data-lake-id="uc1456f9d" id="uc1456f9d"><span data-lake-id="u888b3f3e" id="u888b3f3e">Unsafe中提供了一个静态的getUnsafe方法，可以返回一个unsafe的实例，但是这个只有在Bootstrap类加载器中可以使用，否则会抛出SecurityException</span></p>
  </blockquote>
  <h2 data-lake-id="XH4Jw" id="XH4Jw"><span data-lake-id="u3ff5b94f" id="u3ff5b94f">分配内存</span></h2>
  <p data-lake-id="uc7729906" id="uc7729906"><br></p>
  <p data-lake-id="u0ff234d1" id="u0ff234d1"><span data-lake-id="u79f66e5d" id="u79f66e5d">unsafe中提供了allocateMemory方法来分配堆外内存，freeMemory方法来释放堆外内存。</span></p>
  <p data-lake-id="u61fe1511" id="u61fe1511"><span data-lake-id="uc0f8149b" id="uc0f8149b">​</span><br></p>
  <pre lang="java"><code>
import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class UnsafeExample {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        // 使用反射获取Unsafe实例
        Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafeField.get(null);

        // 分配堆外内存，返回内存地址
        long size = 1024; // 内存大小
        long address = unsafe.allocateMemory(size);

        // 写入数据到堆外内存
        String dataToWrite = "Hello, this is hollis testing direct memory!";
        byte[] dataBytes = dataToWrite.getBytes();
        for (int i = 0; i &lt; dataBytes.length; i++) {
            unsafe.putByte(address + i, dataBytes[i]);
        }

        // 从堆外内存读取数据
        byte[] dataToRead = new byte[dataBytes.length];
        for (int i = 0; i &lt; dataBytes.length; i++) {
            dataToRead[i] = unsafe.getByte(address + i);
        }

        System.out.println(new String(dataToRead));

        // 释放堆外内存
        unsafe.freeMemory(address);
    }
}


输出结果：Hello, this is hollis testing direct memory!
</code></pre>
  <p data-lake-id="ubea28f8f" id="ubea28f8f"><span data-lake-id="ub66092ae" id="ub66092ae">​</span><br></p>
  <h2 data-lake-id="p8MJG" id="p8MJG"><span data-lake-id="u5630ec99" id="u5630ec99">CAS操作</span></h2>
  <p data-lake-id="uf9d8c895" id="uf9d8c895"><br></p>
  <p data-lake-id="u9a413794" id="u9a413794"><span data-lake-id="u7eaac8ce" id="u7eaac8ce">使用Unsafe也可以实现一个CAS操作：</span></p>
  <p data-lake-id="u4dd6c5ab" id="u4dd6c5ab"><span data-lake-id="u09162e13" id="u09162e13">​</span><br></p>
  <pre lang="java"><code>
import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class CASExample {
    private static Unsafe unsafe;

    static {
        try {
            // 使用反射获取Unsafe实例
            Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafeField.setAccessible(true);
            unsafe = (Unsafe) theUnsafeField.get(null);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private static class Counter {
        private volatile int value;

        public Counter(int initialValue) {
            this.value = initialValue;
        }

        // CAS操作
        public void increment() {
            int current;
            int next;
            do {
                current = value;
                next = current + 1;
            } while (!unsafe.compareAndSwapInt(this, valueOffset, current, next));
        }
    }

    // 获取value字段在Counter对象中的偏移量
    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset(Counter.class.getDeclaredField("value"));
        } catch (NoSuchFieldException e) {
            throw new Error(e);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter(0);

        // 创建多个线程并发更新计数器
        Thread[] threads = new Thread[10];
        for (int i = 0; i &lt; threads.length; i++) {
            threads[i] = new Thread(() -&gt; {
                for (int j = 0; j &lt; 1000; j++) {
                    counter.increment();
                }
            });
            threads[i].start();
        }

        // 等待所有线程完成
        for (Thread thread : threads) {
            thread.join();
        }

        // 输出最终计数值
        System.out.println("Final counter value: " + counter.value);
    }
}


输出结果：Final counter value: 10000

</code></pre>
 </body>
</html>